package com.roosterrobotics.replicant;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import com.roosterrobotics.replicant.provider.ReplicantData;

import android.app.Activity;
import android.content.ContentProvider;
import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.location.GpsStatus.Listener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;


public class DeviceDetail extends Activity {

	private ContentProviderClient client;
	private ContentProvider provider;
	
	//private ExpandableListView mSensorList;
	private ListView mSensorList;
	private ListView mActuatorList;
	private TextView mDeviceBreadcrumb;
	private Button mDetectButton;
	private ImageButton mLockImageButton;
	private TextView mDeviceAddress;
	private TextView mReplicantStatus;
	private String address = null;
	private String name = null;
	private Long port = null;
	private Long devId = null;
	private Long commId = null;
	private String commName = "";
	private boolean lock = false;
	private boolean replicant = false;
	
	private static final String REPCOM = "RepCom";
	private static final String REPDEV = "RepDev";
	// End of message mark;
	private static final String EOM = "#";
	private static final String REPLOCK = "RepLock";
	private static final String REPUNLOCK = "RepUnlock";
	private static final String ACCEPT = "Accept";
	private static final String DENY = "Deny";
	private static final String REPSENSORSQUERY = "RepSensorsQuery";
	private static final String REPSENSORSRESPONSE = "RepSensorsResponse";
	private static final String REPACTUATORSQUERY = "RepActuatorsQuery";
	private static final String REPACTUATORSRESPONSE = "RepActuatorsResponse";
	
	
	/**
	 * 
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		Resources res = getResources();
		
	    client = getContentResolver().acquireContentProviderClient(ReplicantData.AUTHORITY);
	    provider = client.getLocalContentProvider();
		setContentView(R.layout.device_detail_tabs);
		setTitle(R.string.device_detail);	
		//mSensorList = getExpandableListView();
		mDeviceBreadcrumb = (TextView) findViewById(R.id.deviceBreadcrumb);
		mDetectButton = (Button) findViewById(R.id.detectButton);
		mLockImageButton = (ImageButton) findViewById(R.id.lockImageButton);
		mDeviceAddress = (TextView) findViewById(R.id.deviceAddress);
		mReplicantStatus = (TextView) findViewById(R.id.replicantStatus);
		
		mSensorList = (ListView) findViewById(R.id.sensorList);
		mSensorList.setEmptyView((TextView) findViewById(R.id.emptySensors));

		mActuatorList = (ListView) findViewById(R.id.actuatorList);		
		mActuatorList.setEmptyView((TextView) findViewById(R.id.emptyActuators));

		TabHost tabs = (TabHost) findViewById(android.R.id.tabhost);
		tabs.setup();
		
		TabHost.TabSpec spec = tabs.newTabSpec("Replicant");
		spec.setContent(R.id.tab1);
		spec.setIndicator(res.getText(R.string.replicant), res.getDrawable(R.drawable.ic_tab_replicant));
		
		tabs.addTab(spec);
		
		spec = tabs.newTabSpec("Sensors");
		spec.setContent(R.id.tab2);
		spec.setIndicator(res.getText(R.string.sensors), res.getDrawable(R.drawable.ic_tab_satellite));
		
		tabs.addTab(spec);
		
		spec = tabs.newTabSpec("Actuators");
		spec.setContent(R.id.tab3);
		spec.setIndicator(res.getText(R.string.actuators), res.getDrawable(R.drawable.ic_tab_gears));
		
		tabs.addTab(spec);
		
		tabs.setCurrentTab(0);
		
		
		Bundle extras = getIntent().getExtras();	
		
		if (extras != null) {
			devId = extras.getLong(ReplicantData.Devices.DEVICE_ID_COLUMN_NAME);
			commId = extras.getLong(ReplicantData.Devices.DEVICE_COMMUNITY_COLUMN_NAME);
			Cursor c = provider.query(Uri.parse(ReplicantData.Communities.CONTENT_URI + "/" + String.valueOf(commId)), null, null, null, null);
			if (c != null) {
				c.moveToFirst();
				commName = c.getString(c.getColumnIndex(ReplicantData.Communities.COMMUNITY_NAME_COLUMN_NAME));
				c.close();
			}
			
			c = provider.query(Uri.parse(ReplicantData.Devices.CONTENT_URI + "/" + String.valueOf(devId)), null, null, null,null);
			if (c != null) {
				c.moveToFirst();
				name = c.getString(c.getColumnIndex(ReplicantData.Devices.DEVICE_NAME_COLUMN_NAME)); 
				mDeviceBreadcrumb.setText(commName + " >> " + name);
				address = c.getString(c.getColumnIndex(ReplicantData.Devices.DEVICE_ADDRESS_COLUMN_NAME));
				port = c.getLong(c.getColumnIndex(ReplicantData.Devices.DEVICE_PORT_COLUMN_NAME));
				mDeviceAddress.setText(address + ":" + String.valueOf(port));
				lock = c.getInt(c.getColumnIndex(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME)) > 0;
				if (lock) {
					mLockImageButton.setImageResource(R.drawable.lock);
				}
				else {
					mLockImageButton.setImageResource(R.drawable.lockopen);
				}
				replicant = c.getInt(c.getColumnIndex(ReplicantData.Devices.DEVICE_REPLICANT_COLUMN_NAME)) > 0;
				if (replicant) {
					mReplicantStatus.setText(R.string.replicant);
				}
				else {
					mReplicantStatus.setText(R.string.not_checked_replicant);
				}
				mLockImageButton.setEnabled(replicant);
				mDetectButton.setEnabled(!replicant);
				c.close();
				fillSensorData();
				fillActuatorData();
			}
			
		}
		
		
		mDetectButton.setOnClickListener(new View.OnClickListener() {			
			public void onClick(View v) {
					new NetworkMessenger(REPCOM).execute(address, String.valueOf(port), REPCOM + " " + commName + EOM);
			}
		});
		
		
		mLockImageButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				if (!lock) {
					new NetworkMessenger(REPLOCK).execute(address, String.valueOf(port), REPLOCK + " " + commName + " " + name + " myApp" + EOM);
				}
				else {
					new NetworkMessenger(REPUNLOCK).execute(address, String.valueOf(port), REPUNLOCK + " " + commName + " " + name + " myApp" + EOM);
				}
			}
		});
		
		tabs.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
			@Override
			public void onTabChanged(String tabId) {
				if (tabId == "Sensors") {
					if (mSensorList.getCount() == 0) {
						new NetworkMessenger(REPSENSORSQUERY).execute(address, String.valueOf(port), REPSENSORSQUERY + " " + commName + " " + name + EOM);	
				
					}
				}
				else if (tabId == "Actuators") {
					if (mActuatorList.getCount() == 0) {
						new NetworkMessenger(REPACTUATORSQUERY).execute(address, String.valueOf(port), REPACTUATORSQUERY + " " + commName + " " + name + EOM);	
				
					}
				}
			}
		}
		
		);
		
		mSensorList.setOnItemClickListener(new OnItemClickListener() {
	       	public void onItemClick(AdapterView <?> parent, View view, int position, long id) {
        		Cursor c = provider.query(Uri.parse(ReplicantData.Sensors.CONTENT_URI + "/" + String.valueOf(id)),
        				null, null, null, null);
        		if (c != null) {
        			c.moveToFirst();
        			String sName = c.getString(c.getColumnIndex(ReplicantData.Sensors.SENSOR_NAME_COLUMN_NAME));
        			String units = c.getString(c.getColumnIndex(ReplicantData.Sensors.SENSOR_UNITS_COLUMN_NAME));
        			Long int_id = c.getLong(c.getColumnIndex(ReplicantData.Sensors.SENSOR_INTERNAL_ID_COLUMN_NAME));
        			boolean isDigital = c.getInt(c.getColumnIndex(ReplicantData.Sensors.SENSOR_ISDIGITAL_COLUMN_NAME)) > 0;
        			Long device = c.getLong(c.getColumnIndex(ReplicantData.Sensors.SENSOR_DEVICE_COLUMN_NAME));
        			Bundle b = new Bundle();
        			b.putString(ReplicantData.Sensors.SENSOR_NAME_COLUMN_NAME, sName);
        			b.putString(ReplicantData.Sensors.SENSOR_UNITS_COLUMN_NAME, units);
        			b.putLong(ReplicantData.Sensors.SENSOR_INTERNAL_ID_COLUMN_NAME, int_id);
        			b.putBoolean(ReplicantData.Sensors.SENSOR_ISDIGITAL_COLUMN_NAME, isDigital);
        			b.putLong(ReplicantData.Sensors.SENSOR_DEVICE_COLUMN_NAME, device);
        			b.putString("CommunityName", commName);
        			b.putString("DeviceName", name);
        			b.putString(ReplicantData.Devices.DEVICE_ADDRESS_COLUMN_NAME, address);
        			b.putLong(ReplicantData.Devices.DEVICE_PORT_COLUMN_NAME, port);
        			c.close();
        			Intent i = new Intent(DeviceDetail.this, SensorDetail.class);
        			i.putExtras(b);
        			startActivity(i);	
        		}
        	}
		
		}
		);
		
		mActuatorList.setOnItemClickListener(new OnItemClickListener() {
	       	public void onItemClick(AdapterView <?> parent, View view, int position, long id) {
        		Cursor c = provider.query(Uri.parse(ReplicantData.Actuators.CONTENT_URI + "/" + String.valueOf(id)),
        				null, null, null, null);
        		if (c != null) {
        			c.moveToFirst();
        			String aName = c.getString(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_NAME_COLUMN_NAME));
        			Long maxValue = c.getLong(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_MAXVALUE));
        			Long minValue = c.getLong(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_MINVALUE));
        			Long int_id = c.getLong(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_INTERNAL_ID_COLUMN_NAME));
        			boolean feedback = c.getInt(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_FEEDBACK_COLUMN_NAME)) > 0;
        			Long device = c.getLong(c.getColumnIndex(ReplicantData.Actuators.ACTUATOR_DEVICE_COLUMN_NAME));
        			c.close();
        			Bundle b = new Bundle();
        			b.putString(ReplicantData.Actuators.ACTUATOR_NAME_COLUMN_NAME, aName);
        			b.putLong(ReplicantData.Actuators.ACTUATOR_MAXVALUE, maxValue);
        			b.putLong(ReplicantData.Actuators.ACTUATOR_MINVALUE, minValue);
        			b.putLong(ReplicantData.Actuators.ACTUATOR_INTERNAL_ID_COLUMN_NAME, int_id);
        			b.putBoolean(ReplicantData.Actuators.ACTUATOR_FEEDBACK_COLUMN_NAME, feedback);
        			b.putLong(ReplicantData.Actuators.ACTUATOR_DEVICE_COLUMN_NAME, device);
        			b.putString("CommunityName", commName);
        			b.putString("DeviceName", name);
        			b.putString(ReplicantData.Devices.DEVICE_ADDRESS_COLUMN_NAME, address);
        			b.putLong(ReplicantData.Devices.DEVICE_PORT_COLUMN_NAME, port);
        			c.close();
        			Intent i = new Intent(DeviceDetail.this, ActuatorDetail.class);
        			i.putExtras(b);
        			startActivity(i);	
        		}
        	}
		
		}
		);
			
		
	}
	
	private void fillSensorData() {
		if (devId != null) {
			Cursor cSensors = provider.query(Uri.parse(ReplicantData.Sensors.CONTENT_URI + "/" 
			+ ReplicantData.Devices.DEVICE_NAME + "/" + String.valueOf(devId)), null, null, null, null);
			
			startManagingCursor(cSensors);
	    	
			String[] fromSensors = new String[] {ReplicantData.Sensors.SENSOR_NAME_COLUMN_NAME};
	    	int[] toSensors = new int[] {R.id.sensorName};
	    	
	    	SimpleCursorAdapter sensors = new SimpleCursorAdapter(this, R.layout.sensors_row, cSensors, fromSensors, toSensors);
	    	mSensorList.setAdapter(sensors);
	    	
		}
	}
	
	private void fillActuatorData() {
		if (devId != null) {
			
			Cursor cActuators = provider.query(Uri.parse(ReplicantData.Actuators.CONTENT_URI + "/" 
				+ ReplicantData.Devices.DEVICE_NAME + "/" + String.valueOf(devId)), null, null, null, null);
			startManagingCursor(cActuators);
	    	
			String[] fromActuators = new String[] {ReplicantData.Actuators.ACTUATOR_NAME_COLUMN_NAME};
	    	int[] toActuators = new int[] {R.id.actuatorName};
	    	
	    	SimpleCursorAdapter actuators = new SimpleCursorAdapter(this, R.layout.actuators_row, cActuators, fromActuators, toActuators);
	    	mActuatorList.setAdapter(actuators);
	    	
		}
	}
	
	// Address, port, msg
	private class NetworkMessenger extends AsyncTask<String, Void, String> {
		PrintWriter out = null;
		BufferedReader in = null;
		Socket s = null;
		String msg;
		
		public NetworkMessenger(String m) {
			super();
			msg = m;
		}
		
		protected String doInBackground(String...strings) {
			String buffer = "";
			char a;

			try {
				s = new Socket(strings[0], Long.decode(strings[1]).intValue());
				out = new PrintWriter(s.getOutputStream());
				in = new BufferedReader(new InputStreamReader(s.getInputStream()));
				
				while (in.ready()) {
					a  = (char) in.read();
				}	
				msg = strings[2];
				out.println(msg);
				out.flush();
				buffer = in.readLine();
				out.close();
				in.close();
				s.close();
				// If there isn't a response but the connection was established.
				if (buffer == null) {
					buffer = "Error: Device not responding";
				}
			} catch (NumberFormatException e) {
				buffer = "Exception: Address format incorrect";
				return buffer;
			} catch (UnknownHostException e) {
				buffer = "Exception: Unknown host";
				return buffer;
			} catch (IOException e) {
				buffer = "Exception: I/O Error";
				return buffer;
			}
			return buffer;
		}
		
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			
			if (msg.startsWith(REPCOM)) {
				mReplicantStatus.setText(R.string.checking);
			}
			
		}
		
		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			ContentValues values = new ContentValues();
			values.put(ReplicantData.Devices.DEVICE_ID_COLUMN_NAME, devId);
			values.put(ReplicantData.Devices.DEVICE_NAME_COLUMN_NAME, name);
			values.put(ReplicantData.Devices.DEVICE_COMMUNITY_COLUMN_NAME, commId);
			values.put(ReplicantData.Devices.DEVICE_ADDRESS_COLUMN_NAME, address);
			values.put(ReplicantData.Devices.DEVICE_PORT_COLUMN_NAME, port);
			values.put(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME, lock);
			values.put(ReplicantData.Devices.DEVICE_REPLICANT_COLUMN_NAME, replicant);
			if (result.startsWith("Error:") || result.startsWith("Exception:")) {
				Toast toast = Toast.makeText(DeviceDetail.this, result, Toast.LENGTH_LONG);
				toast.show();
			}
			else if (msg.startsWith(REPCOM)) {
				if (result.startsWith("RepDev")) {				
					mReplicantStatus.setText(R.string.replicant);
					// It's a replicant.
					values.put(ReplicantData.Devices.DEVICE_REPLICANT_COLUMN_NAME, true);
					provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null); 
					mLockImageButton.setEnabled(true);

				}
				else if (result.startsWith("Error")){
					mReplicantStatus.setText(R.string.not_a_replicant);
					values.put(ReplicantData.Devices.DEVICE_REPLICANT_COLUMN_NAME, false);
					provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
				}
				else {
					mReplicantStatus.setText(R.string.not_checked_replicant);
					values.put(ReplicantData.Devices.DEVICE_REPLICANT_COLUMN_NAME, false);
					provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
				}
			}
			else if (msg.startsWith(REPLOCK)) {
				if (result.startsWith(REPLOCK)) {
					int i = result.indexOf(" ");
					String response = result.substring(i + 1, result.length() - 1);
					if (response.equals(ACCEPT)) {
						lock = true;
						mLockImageButton.setImageResource(R.drawable.lock);
						values.put(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME, true);
						provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
					}
					else {
						lock = false;
						mLockImageButton.setImageResource(R.drawable.lockopen);
						values.put(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME, false);
						provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
					}
				}
			}
			else if (msg.startsWith(REPUNLOCK)) {
				int i = result.indexOf(" ");
				String response = result.substring(i + 1, result.length() - 1);
				if (response.equals(ACCEPT)) {
					lock = false;
					mLockImageButton.setImageResource(R.drawable.lockopen);
					values.put(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME, false);
					provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
				}
				else {
					lock = true;
					mLockImageButton.setImageResource(R.drawable.lock);
					values.put(ReplicantData.Devices.DEVICE_LOCK_COLUMN_NAME, true);
					provider.update(Uri.parse(ReplicantData.Devices.DEVICES_URI + "/" + String.valueOf(devId)), values, null, null);
				}
			}
			else if (msg.startsWith(REPSENSORSQUERY)) {
				proccessSensorsResponse(result);
				fillSensorData();
				
			}
			else if(msg.startsWith(REPACTUATORSQUERY)) {
				proccessActuatorsResponse(result);
				fillActuatorData();
			}
		}
		
		private void proccessSensorsResponse(String result) {
			int i = result.indexOf(" ");
			String devName;
			Long numSensors;
			Long sId;
			String sName;
			String sUnits;
			String isDigital;
			boolean sDigital;
			
			String sResp = result.substring(i + 1, result.length() - 1);
			i = sResp.indexOf(" ");
			devName = sResp.substring(0, i);
			sResp = sResp.substring(i + 1);
			i = sResp.indexOf(" ");
			numSensors = Long.decode(sResp.substring(0, i));
			sResp = sResp.substring(i + 1);
			for (int idx = 0; idx < numSensors; idx++) {
				i = sResp.indexOf(" ");
				sId = Long.decode(sResp.substring(0, i));
				sResp = sResp.substring(i + 1);
				int j = 0;
				i = sResp.indexOf("\"");
				j = sResp.indexOf("\"", i + 1);
				sName = sResp.substring(i + 1, j);
				// There's must be an additional whitespace.
				sResp = sResp.substring(j + 2);
				i = sResp.indexOf(" ");
				sUnits = sResp.substring(0, i);
				sResp = sResp.substring(i + 1);
				if (idx == numSensors - 1) {
					i = sResp.length();
					isDigital = sResp.substring(0, i);
				}
				else {
					i = sResp.indexOf(" ");
					isDigital = sResp.substring(0, i);
					sResp = sResp.substring(i + 1);
				}
				sDigital = isDigital.equals("true");
				
        		Uri retUri;

        		ContentValues values = new ContentValues();
        		values.put(ReplicantData.Sensors.SENSOR_NAME_COLUMN_NAME, sName);
        		values.put(ReplicantData.Sensors.SENSOR_UNITS_COLUMN_NAME, sUnits);
        		values.put(ReplicantData.Sensors.SENSOR_ISDIGITAL_COLUMN_NAME, sDigital);
        		values.put(ReplicantData.Sensors.SENSOR_INTERNAL_ID_COLUMN_NAME, sId);
        		values.put(ReplicantData.Sensors.SENSOR_DEVICE_COLUMN_NAME, devId);
        		retUri = provider.insert(ReplicantData.Sensors.SENSORS_URI, values);
        		long val = ContentUris.parseId(retUri);
			}
		}
		
		private void proccessActuatorsResponse(String result) {
			String devName;
			Long numActuators;
			Long aId;
			String aName;
			Long aMinValue;
			Long aMaxValue;
			String feedBack;
			Boolean aFeedBack;
			
			int i = result.indexOf(" ");
			String sResp = result.substring(i + 1, result.length() - 1);
			i = sResp.indexOf(" ");
			devName = sResp.substring(0, i);
			sResp = sResp.substring(i + 1);
			i = sResp.indexOf(" ");
			numActuators = Long.decode(sResp.substring(0, i));
			sResp = sResp.substring(i + 1);
			for (int idx = 0; idx < numActuators; idx++) {
				i = sResp.indexOf(" ");
				aId = Long.decode(sResp.substring(0, i));
				sResp = sResp.substring(i + 1);
				int j = 0;
				i = sResp.indexOf("\"");
				j = sResp.indexOf("\"", i + 1);
				aName = sResp.substring(i + 1, j);
				// There's must be an additional whitespace.
				sResp = sResp.substring(j + 2);
				i = sResp.indexOf(" ");
				aMinValue = Long.decode(sResp.substring(0, i));
				sResp = sResp.substring(i + 1);
				i = sResp.indexOf(" ");
				aMaxValue = Long.decode(sResp.substring(0, i));
				sResp = sResp.substring(i + 1);
				if (idx == numActuators - 1) {
					i = sResp.length();
					feedBack = sResp.substring(0, i);
				}
				else {
					i = sResp.indexOf(" ");
					feedBack = sResp.substring(0, i);
					sResp = sResp.substring(i + 1);
				}
				aFeedBack = feedBack.equals("true");
				
        		Uri retUri;

        		ContentValues values = new ContentValues();
        		values.put(ReplicantData.Actuators.ACTUATOR_NAME_COLUMN_NAME, aName);
        		values.put(ReplicantData.Actuators.ACTUATOR_INTERNAL_ID_COLUMN_NAME, aId);
        		values.put(ReplicantData.Actuators.ACTUATOR_MINVALUE, aMinValue);
        		values.put(ReplicantData.Actuators.ACTUATOR_MAXVALUE, aMaxValue);
        		values.put(ReplicantData.Actuators.ACTUATOR_FEEDBACK_COLUMN_NAME, aFeedBack);
        		values.put(ReplicantData.Actuators.ACTUATOR_DEVICE_COLUMN_NAME, devId);
        		
        		retUri = provider.insert(ReplicantData.Actuators.ACTUATORS_URI, values);
        		long val = ContentUris.parseId(retUri);
			}	
		}
	}
}
